#include "xlate.h"
#include <stdio.h>

#define HAVE_REMOTE    // This must be defined before "pcap.h"
#include <pcap.h>

#include "global.h"
#include "headers.h"

#include "arp.h"
#include "ip.h"
#include "icmp.h"
#include "tcp.h"

// Compare two char arrays of the same length
int char_array_equal( const u_char *array1, const u_char *array2, const int len )
{
	int i;
	int ret = 1; // Set to true at first

	for( i = 0; i < len; i++ ) {
		if( array1[i] != array2[i] ) // Any differences will result a false return
			ret = 0;
	}

	return ret;
}

void xlate4to6( void * )  // 4to6 translation thread
{
	int res = 0;

	/* Retrieve the packets */
    while(WaitForSingleObject( v4RunMutex, 75L ) == WAIT_TIMEOUT 
		&& (res = pcap_next_ex( v4Handle, &v4Header, &v4RecvBuffer)) >= 0)
	{
        if(res == 0)
            /* Timeout elapsed */
            continue;

		//printf("v4 device: packet captured!\n");

		eth_header *eh;
		eh = (eth_header *)v4RecvBuffer;

		// Dispatch
		if( eh->type == htons(ETH_ARP) ) // ARP Packet
		{
			// Reply this request with v6GatewayMAC
			arp_header *ah;
			ah = (arp_header *)( v4RecvBuffer + sizeof(eth_header));
			if( ah->option == htons(ARP_REQUEST) ) //ARP Request
			{
				arp_reply( eh, ah );
			}
			// Done with ARP
		}
		else if( eh->type == htons(ETH_IP) ) // IPv4 Packet
		{
			if( char_array_equal( eh->smac, v4LocalMAC, 6 ) == 0 ) {
				// Do not handle non-local-sent packets
				//printf("v4 device: non-local-sent packets ignored!\n");
				continue;
			}

			ip_header *ih;
			ih = (ip_header *)( v4RecvBuffer + sizeof(eth_header));

			// Dispatch
			if( ih->protocol == IP_ICMP ) // ICMP Packet
			{
				icmp_header *icmph;
				icmph = (icmp_header *)( v4RecvBuffer + sizeof(eth_header) + (ih->ver_ihl & 0x0f) * 4);
				icmp4to6( eh, ih, icmph );
			}
			else if( ih->protocol == IP_TCP ) // TCP Packet
			{
				tcp_header *th;
				th = (tcp_header *)( v4RecvBuffer + sizeof(eth_header) + (ih->ver_ihl & 0x0f) * 4);
				tcp4to6( eh, ih, th );
			}
			else if( ih->protocol == IP_UDP ) // UDP Packet
			{
				// to be implemented
			}
		}

    }
    
    if(res == -1){
        printf("Error reading the packets: %s\n", pcap_geterr(v4Handle));
    }

	return;
}

void xlate6to4( void * )  // 6to4 translation thread
{
	int res = 0;

	/* Retrieve the packets */
    while(WaitForSingleObject( v6RunMutex, 75L ) == WAIT_TIMEOUT 
		&& (res = pcap_next_ex( v6Handle, &v6Header, &v6RecvBuffer)) >= 0)
	{
        if(res == 0)
            /* Timeout elapsed */
            continue;
        
		//printf("v6 device: packet captured!\n");

		eth_header *eh;
		eh = (eth_header *)v6RecvBuffer;

		// Dispatch
		if( eh->type == htons(ETH_IP6) ) // IPv6 Packet
		{
			if( char_array_equal( eh->dmac, v6LocalMAC, 6 ) == 0 ) {
				// Do not handle non-local-destinated packets
				//printf("v6 device: non-local-destinated packets ignored!\n");
				continue;
			}

			ip6_header *ip6h;
			ip6h = (ip6_header *)( v6RecvBuffer + sizeof(eth_header));

			if( ip6h->nexthdr == IP_ICMP6 ) // ICMPv6 Packet
			{
				icmp6_header *icmp6h;
				icmp6h = (icmp6_header *)( v6RecvBuffer + sizeof(eth_header) + sizeof(ip6_header) );
				icmp6to4( eh, ip6h, icmp6h );
			}
			else if( ip6h->nexthdr == IP_TCP ) // TCP Packet
			{
				tcp_header *th;
				th = (tcp_header *)( v6RecvBuffer + sizeof(eth_header) + sizeof(ip6_header) );
				tcp6to4( eh, ip6h, th );
			}
			else if( ip6h->nexthdr == IP_UDP ) // UDP Packet
			{
				// to be implemented
			}
		}

	}

	if(res == -1){
        printf("Error reading the packets: %s\n", pcap_geterr(v6Handle));
    }

	return;
}
